package com.hsjk.szwj.module.pay.service;

import cn.hutool.core.util.IdUtil;
import cn.hutool.extra.spring.SpringUtil;
import com.hsjk.szwj.framework.common.exception.ServiceException;
import com.hsjk.szwj.framework.common.exception.enums.GlobalErrorCodeConstants;
import com.hsjk.szwj.framework.common.util.string.StringKit;
import com.hsjk.szwj.module.pay.controller.PayApiController;
import com.hsjk.szwj.module.pay.controller.app.transfer.vo.TransferOrderReqVO;
import com.hsjk.szwj.module.pay.controller.app.transfer.vo.TransferOrderRespVO;
import com.hsjk.szwj.module.pay.dal.dataobject.CommonPayResult;
import com.hsjk.szwj.module.pay.dal.dataobject.config.ChannelRetMsg;
import com.hsjk.szwj.module.pay.dal.dataobject.config.MchAppConfigContext;
import com.hsjk.szwj.module.pay.dal.dataobject.order.PayOrderDO;
import com.hsjk.szwj.module.pay.dal.dataobject.order.TransferOrderDO;
import com.hsjk.szwj.module.pay.dal.dataobject.system.MchAppDO;
import com.hsjk.szwj.module.pay.dal.dataobject.system.MchInfoDO;
import com.hsjk.szwj.module.pay.exception.ChannelException;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.time.LocalDateTime;

/**
 * @author chenjiawei
 * @desc
 * @Date 2023/10/17 22:15
 **/
@Service
@Slf4j
public class TransferOrderServiceImpl extends PayApiController implements ITransferOrderService {
    @Resource
    private ConfigContextQueryService configContextQueryService;
    @Resource
    private TransferOrderService transferOrderService;
    @Resource
    private PayInterfaceConfigService payInterfaceConfigService;
    @Resource
    private PayMchNotifyService payMchNotifyService;

    @Resource
    private PayInterfaceDefineService payInterfaceDefineService;

    @Resource
    private IMchInfoService mchInfoService;

    @Resource
    private IMchAppService mchAppService;

    @Resource
    private IPayService payService;

    @Override
    public CommonPayResult transferOrder(TransferOrderReqVO reqVO) {
        TransferOrderDO transferOrder = null;
        MchInfoDO mchInfoDO = mchInfoService.getMchInfoByTenant();
        PayOrderDO payOrderById = payService.getPayOrderById(reqVO.getPayOrderId());
        MchAppDO mchAppDO = mchAppService.getById(payOrderById.getAppId());
        Long mchId = mchInfoDO.getId();
        Long appId = mchAppDO.getId();
        try {
            Long ifId = payInterfaceDefineService.getIdByCode(reqVO.getIfCode());

            if (StringUtils.isNotEmpty(reqVO.getNotifyUrl())
                    && !StringKit.isAvailableUrl(reqVO.getNotifyUrl())) {
                throw new ServiceException(GlobalErrorCodeConstants.BAD_REQUEST.getCode(),
                        "异步通知地址协议仅支持http:// 或 https:// !");
            }

            // 商户配置信息
            MchAppConfigContext mchAppConfigContext
                    = configContextQueryService.queryMchInfoAndAppInfo(mchId, appId);
            if (mchAppConfigContext == null) {
                throw new ServiceException(GlobalErrorCodeConstants.BAD_REQUEST.getCode(),
                        "获取商户应用信息失败");
            }

            MchInfoDO mchInfo = mchAppConfigContext.getMchInfo();
            MchAppDO mchApp = mchAppConfigContext.getMchApp();

            // 是否已正确配置
            if (!payInterfaceConfigService.mchAppHasAvailableIfCode(appId, ifId)) {
                throw new ServiceException(GlobalErrorCodeConstants.BAD_REQUEST.getCode(),
                        "应用未开通此接口配置!");
            }


            ITransferService transferService
                    = SpringUtil.getBean(reqVO.getIfCode() + "TransferService",
                    ITransferService.class);
            if (transferService == null) {
                throw new ServiceException(GlobalErrorCodeConstants.BAD_REQUEST.getCode(),
                        "无此转账通道接口");
            }

            if (!transferService.isSupport(reqVO.getEntryType())) {
                throw new ServiceException(GlobalErrorCodeConstants.BAD_REQUEST.getCode(),
                        "该接口不支持该入账方式");
            }

            transferOrder = genTransferOrder(reqVO, mchInfo, mchApp, reqVO.getIfCode());

            //预先校验
            String errMsg = transferService.preCheck(reqVO, transferOrder);
            if (StringUtils.isNotEmpty(errMsg)) {
                throw new ServiceException(GlobalErrorCodeConstants.BAD_REQUEST.getCode(),
                        errMsg);
            }

            // 入库
            transferOrderService.save(transferOrder);

            // 调起上游接口
            ChannelRetMsg channelRetMsg = transferService.transfer(reqVO, transferOrder, mchAppConfigContext);

            //处理退款单状态
            this.processChannelMsg(channelRetMsg, transferOrder);

            TransferOrderRespVO bizRes = TransferOrderRespVO.buildByRecord(transferOrder);
            return CommonPayResult.okWithSign(bizRes, mchApp.getAppSecret());

        } catch (ServiceException e) {
            return CommonPayResult.error(e.getMessage());

        } catch (ChannelException e) {

            //处理上游返回数据
            this.processChannelMsg(e.getChannelRetMsg(), transferOrder);

            if (e.getChannelRetMsg().getChannelState() == ChannelRetMsg.ChannelState.SYS_ERROR) {
                return CommonPayResult.error(e.getMessage());
            }

            TransferOrderRespVO bizRes = TransferOrderRespVO.buildByRecord(transferOrder);
            return CommonPayResult.okWithSign(bizRes,
                    configContextQueryService.queryMchApp(mchId,
                            appId).getAppSecret());

        } catch (Exception e) {
            log.error("系统异常：{}", e);
            return CommonPayResult.error("系统异常");
        }
    }

    private TransferOrderDO genTransferOrder(TransferOrderReqVO rq,
                                             MchInfoDO mchInfo, MchAppDO mchApp,
                                             String ifCode) {

        TransferOrderDO transferOrder = new TransferOrderDO();
        //商户号
        transferOrder.setMchId(mchInfo.getId());
        //服务商号
        transferOrder.setIsvId(mchInfo.getIsvId());
        //商户应用appId
        transferOrder.setAppId(mchApp.getId());
        //商户名称（简称）
        transferOrder.setMchName(mchInfo.getMchShortName());
        //商户类型
        transferOrder.setMchType(mchInfo.getMchType());
        //商户订单号
//        long orderId = IdUtil.getSnowflakeNextId();
        transferOrder.setMchOrderId(rq.getPayOrderId());
        //接口代码
        transferOrder.setIfCode(ifCode);
        //入账方式
        transferOrder.setEntryType(rq.getEntryType());
        //订单金额
        transferOrder.setAmount(rq.getAmount());
        //币种
        transferOrder.setCurrency(rq.getCurrency());
        //客户端IP
        transferOrder.setClientIp(StringUtils.defaultIfEmpty(rq.getClientIp(),
                getClientIp()));
        //订单状态, 默认订单生成状态
        transferOrder.setState(TransferOrderDO.STATE_INIT);
        //收款账号
        transferOrder.setAccountNo(rq.getAccountNo());
        //账户姓名
        transferOrder.setAccountName(rq.getAccountName());
        //银行名称
        transferOrder.setBankName(rq.getBankName());
        //转账备注
        transferOrder.setTransferDesc(rq.getTransferDesc());
        //商户扩展参数
        transferOrder.setExtParam(rq.getExtParam());
        //异步通知地址
        transferOrder.setNotifyUrl(rq.getNotifyUrl());
        //订单创建时间
        transferOrder.setCreateTime(LocalDateTime.now());
        return transferOrder;

    }


    /**
     * 处理返回的渠道信息，并更新订单状态
     * TransferOrder将对部分信息进行 赋值操作。
     **/
    private void processChannelMsg(ChannelRetMsg channelRetMsg,
                                   TransferOrderDO transferOrder) {

        //对象为空 || 上游返回状态为空， 则无需操作
        if (channelRetMsg == null || channelRetMsg.getChannelState() == null) {
            return;
        }

        Long transferId = transferOrder.getId();

        //明确成功
        if (ChannelRetMsg.ChannelState.CONFIRM_SUCCESS == channelRetMsg.getChannelState()) {

            this.updateInitOrderStateThrowException(TransferOrderDO.STATE_SUCCESS,
                    transferOrder, channelRetMsg);
            payMchNotifyService.transferOrderNotify(transferOrder);

            //明确失败
        } else if (ChannelRetMsg.ChannelState.CONFIRM_FAIL
                == channelRetMsg.getChannelState()) {

            this.updateInitOrderStateThrowException(TransferOrderDO.STATE_FAIL,
                    transferOrder, channelRetMsg);
            payMchNotifyService.transferOrderNotify(transferOrder);

            // 上游处理中 || 未知 || 上游接口返回异常  订单为支付中状态
        } else if (ChannelRetMsg.ChannelState.WAITING == channelRetMsg.getChannelState() ||
                ChannelRetMsg.ChannelState.UNKNOWN == channelRetMsg.getChannelState() ||
                ChannelRetMsg.ChannelState.API_RET_ERROR == channelRetMsg.getChannelState()

        ) {
            this.updateInitOrderStateThrowException(TransferOrderDO.STATE_ING,
                    transferOrder, channelRetMsg);

            // 系统异常：  订单不再处理。  为： 生成状态
        } else if (ChannelRetMsg.ChannelState.SYS_ERROR == channelRetMsg.getChannelState()) {

        } else {

            throw new ServiceException(GlobalErrorCodeConstants.BAD_REQUEST.getCode(),
                    "ChannelState 返回异常！");
        }

    }


    /**
     * 更新订单状态 --》 订单生成--》 其他状态  (向外抛出异常)
     **/
    private void updateInitOrderStateThrowException(Integer orderState,
                                                    TransferOrderDO transferOrder,
                                                    ChannelRetMsg channelRetMsg) {

        transferOrder.setState(orderState);
        transferOrder.setChannelOrderNo(channelRetMsg.getChannelOrderId());
        transferOrder.setErrCode(channelRetMsg.getChannelErrCode());
        transferOrder.setErrMsg(channelRetMsg.getChannelErrMsg());


        boolean isSuccess =
                transferOrderService.updateInit2Ing(transferOrder.getId());
        if (!isSuccess) {
            throw new ServiceException(GlobalErrorCodeConstants.BAD_REQUEST.getCode(),
                    "更新转账订单异常!");
        }

        isSuccess =
                transferOrderService.updateIng2SuccessOrFail(transferOrder.getId(),
                        transferOrder.getState(),
                        channelRetMsg.getChannelOrderId(),
                        channelRetMsg.getChannelErrCode(),
                        channelRetMsg.getChannelErrMsg());
        if (!isSuccess) {
            throw new ServiceException(GlobalErrorCodeConstants.BAD_REQUEST.getCode(),
                    "更新转账订单异常!");
        }
    }
}
